using System;
using System.Collections.Generic;
using System.Linq;
using Ease.EaseNode.Runtime;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;
using Edge = UnityEditor.Experimental.GraphView.Edge;

namespace Ease.EaseNode.Editor.NodeView
{
    public class InitParam
    {
        public int selectID = 0;
    }

    public abstract class BaseEaseChartView : GraphView, IEaseChartView
    {
        public event Action<BaseEaseNode> OnNodeSelected;
        public event Func<Vector2, Vector2> OnGetWindowMousePosition;
        public event Action<Action<IEaseNodeDataState>> OnCreateAllNodes;
        public event Func<Type, IEaseNodeDataState, BaseEaseNode> OnCreateNode;
        public event Action<BaseEaseNode> OnRemoveNode;
        private bool listenToChange = true;
        private InitParam initParam = null;

        public BaseEaseChartView()
        {
            Insert(0, new GridBackground());
            this.AddManipulator(new ContentZoomer());
            this.AddManipulator(new ContentDragger());
            this.AddManipulator(new SelectionDragger());
            this.AddManipulator(new RectangleSelector());

            //当GraphView变化时，调用方法
            graphViewChanged = OnGraphViewChanged;
        }

        //初始化;
        public virtual void Reset(InitParam initParam = null)
        {
            this.initParam = initParam;
            if (this.initParam == null)
                this.initParam = new InitParam();
            listenToChange = false;
            //移除所有节点和边
            List<GraphElement> graphElements = new List<GraphElement>();
            nodes.ForEach(x => graphElements.Add(x));
            edges.ForEach(x => graphElements.Add(x));
            for (int i = 0; i < graphElements.Count; i++)
            {
                RemoveElement(graphElements[i]);
            }

            //Inspector删除
            OnNodeSelected?.Invoke(null);

            //创建
            OnCreateAllNodes?.Invoke((state) => { CreateNode(state.NodePos, state); });
            //创建所有连线。
            CreateNodeEdge();
            //
            SetInitParam(initParam);
            listenToChange = true;
        }

        public virtual void OnEnable()
        {
        }

        public virtual void OnDisable()
        {
            OnNodeSelected?.Invoke(null);
        }

        public virtual void OnUpdate()
        {
        }

        //判断每个点是否可以相连
        public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter)
        {
            return ports.ToList().Where(endPort =>
                endPort.direction != startPort.direction &&
                endPort.node != startPort.node).ToList();
        }

        private GraphViewChange OnGraphViewChanged(GraphViewChange graphViewChange)
        {
            if (listenToChange == false)
                return graphViewChange;
            //对于每个被移除的节点
            if (graphViewChange.elementsToRemove != null)
            {
                graphViewChange.elementsToRemove.ForEach(elem =>
                {
                    if (elem is BaseEaseNode easeNode)
                    {
                        OnRemoveNode?.Invoke(easeNode);
                        OnNodeSelected?.Invoke(null);
                        easeNode.OnNodeRemove();
                    }

                    if (elem is Edge edge)
                    {
                        var parentView = edge.output.node as BaseEaseNode;
                        parentView?.OnEdgeRemove(edge);
                    }
                });
            }

            //对于每个被创建的边
            if (graphViewChange.edgesToCreate != null)
            {
                graphViewChange.edgesToCreate.ForEach(edge =>
                {
                    if (edge.output.node is BaseEaseNode parentView)
                        parentView.OnEdgeCreate(edge);
                });
            }

            //遍历节点，记录位置点
            nodes.ForEach((n) =>
            {
                BaseEaseNode view = n as BaseEaseNode;
                if (view != null && view.State != null)
                {
                    view.State.NodePos = view.GetPosition().position;
                }
            });

            return graphViewChange;
        }

        protected bool OnMenuSelectEntry(SearchTreeEntry searchTreeEntry, SearchWindowContext context)
        {
            var dataStateType = searchTreeEntry.userData as Type;
            if (OnGetWindowMousePosition != null)
            {
                var windowMousePosition = OnGetWindowMousePosition.Invoke(context.screenMousePosition);
                var graphMousePosition = contentViewContainer.WorldToLocal(windowMousePosition);
                CreateNode(graphMousePosition, dataStateType);
            }

            return true;
        }

        private void CreateNodeEdge()
        {
            //获取所有的port,分类：in /out,
            //
            Dictionary<BaseEaseNode, List<Port>> inputPorts = new Dictionary<BaseEaseNode, List<Port>>();
            Dictionary<BaseEaseNode, List<Port>> outputPorts = new Dictionary<BaseEaseNode, List<Port>>();
            HashSet<BaseEaseNode> easeNodes = new HashSet<BaseEaseNode>();
            foreach (var x in ports)
            {
                var y = x.node;
                var node = y as BaseEaseNode;
                easeNodes.Add(node);
                if (node != null)
                {
                    if (x.direction == Direction.Input)
                    {
                        if (!inputPorts.ContainsKey(node))
                        {
                            List<Port> temp = new List<Port>();
                            temp.Add(x);
                            inputPorts.Add(node, temp);
                        }
                        else
                        {
                            var temp = inputPorts[node];
                            if (!temp.Contains(x))
                                temp.Add(x);
                        }
                    }
                    else if (x.direction == Direction.Output)
                    {
                        if (!outputPorts.ContainsKey(node))
                        {
                            List<Port> temp = new List<Port>();
                            temp.Add(x);
                            outputPorts.Add(node, temp);
                        }
                        else
                        {
                            var temp = outputPorts[node];
                            if (!temp.Contains(x))
                                temp.Add(x);
                        }
                    }
                }
            }

            foreach (var easeBaseNode in easeNodes)
            {
                //找到该Node的所有NextIDs;
                foreach (var outPutInfo in easeBaseNode.State.OutputInfos)
                {
                    //找到outPutPort;
                    Port output = outputPorts[easeBaseNode].FirstOrDefault(x => x.name.Equals(outPutInfo.portName));
                    foreach (var key in outPutInfo.portNames)
                    {
                        var keys = key.Split("_");
                        var nodeKey = keys[1];
                        var inputNode = easeNodes.FirstOrDefault(x => x.Key.Equals(nodeKey));
                        if (inputNode != null && inputPorts.TryGetValue(inputNode, out var inputs))
                        {
                            Port input = inputs.FirstOrDefault(x => x.name.Equals(key));
                            AddEdgeByPorts(output, input);
                        }
                    }
                }
            }
        }

        private void CreateNode(Vector2 pos, IEaseNodeDataState state)
        {
            BaseEaseNode newNode = OnCreateNode?.Invoke(state.Data.GetType(), state);
            if (newNode == null)
                return;
            //设置位置;
            newNode.SetPosition(new Rect(pos, newNode.GetPosition().size));
            newNode.OnNodeSelected -= OnNodeSelected;
            newNode.OnNodeSelected += OnNodeSelected;
            newNode.OnNodeCreate(pos);
            OnCreateNewNode(newNode);
            AddElement(newNode);
        }

        /// <summary>
        /// 1 根据类型创建节点，生成类型对象，生成节点。
        /// 2 根据类型对象创建节点，
        /// </summary>
        /// <param name="dataState"></param>
        /// <param name="pos"></param>
        /// <param name="isNew"></param>
        private void CreateNode(Vector2 pos, Type dataState)
        {
            BaseEaseNode newNode = OnCreateNode?.Invoke(dataState, null);
            if (newNode == null)
                return;
            //设置位置;
            newNode.SetPosition(new Rect(pos, newNode.GetPosition().size));
            newNode.OnNodeSelected -= OnNodeSelected;
            newNode.OnNodeSelected += OnNodeSelected;
            newNode.OnNodeCreate(pos);
            OnCreateNewNode(newNode);
            AddElement(newNode);
        }

        //连接两个点
        private void AddEdgeByPorts(Port outputPort, Port inputPort)
        {
            if (outputPort == null || inputPort == null)
                return;
            if (outputPort.node == inputPort.node)
                return;

            Edge tempEdge = new Edge()
            {
                output = outputPort,
                input = inputPort
            };
            tempEdge.input.Connect(tempEdge);
            tempEdge.output.Connect(tempEdge);
            Add(tempEdge);
        }

        protected virtual void SetInitParam(InitParam initParam)
        {
            if (nodes.Count() > 0)
            {
                nodes.FirstOrDefault().Select(this, false);
            }
        }

        protected virtual void OnCreateNewNode(BaseEaseNode newNode)
        {
        }
    }
}